package owg.util.awt;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;

public class StringListEditor extends TypeEditor<ArrayList<String>> implements FocusListener
	{
	static final long serialVersionUID = 2704835030524222876L;
	
	JTextArea area;
	ArrayList<String> values;
	boolean ignoreEvents = false;
	Color origcolor;
	String filter, parseDelimiter, displayDelimiter;
	boolean retainEmptyStrings;
	
	@SuppressWarnings("unchecked")
	public StringListEditor(ArrayList<String> initialValue, 
			String filter, String parseDelimiter, String displayDelimiter, boolean retainEmptyStrings)
		{
		super((Class<ArrayList<String>>) initialValue.getClass());
		this.filter = filter;
		this.parseDelimiter = parseDelimiter;
		this.displayDelimiter = displayDelimiter;
		this.retainEmptyStrings = retainEmptyStrings;
		if(displayDelimiter == null)
			displayDelimiter = " ";
		setLayout(new BorderLayout());
		area = new JTextArea(4,1);
		area.addFocusListener(this);
		/*SO: Carlos Heuberger*/
		InputMap input = area.getInputMap();
	    KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
	    KeyStroke shiftEnter = KeyStroke.getKeyStroke("shift ENTER");
	    input.put(shiftEnter, StringArrayEditor.INSERT_BREAK);  // input.get(enter)) = "insert-break"
	    input.put(enter, StringArrayEditor.TEXT_SUBMIT);

	    ActionMap actions = area.getActionMap();
	    actions.put(StringArrayEditor.TEXT_SUBMIT, new AbstractAction() 
	    	{
			private static final long serialVersionUID = -6245223022744980266L;
			@Override
	        public void actionPerformed(ActionEvent e) 
	        	{
	    		if(!ignoreEvents)
	    			parseValue();
	        	}
	    	});
		
		area.setLineWrap(true);
		area.setWrapStyleWord(true);
		origcolor = area.getBackground();
		setValue(initialValue, false);
		
		JScrollPane pane = new JScrollPane();
		pane.setViewportView(area);
		add(pane, BorderLayout.CENTER);
		area.addFocusListener(this);
		}
	/**Will delete unwanted characters and empty strings.*/
	private void setValue(ArrayList<String> val, boolean fire)
		{
		ArrayList<String> pVal = values;
		values = new ArrayList<String>();
		ignoreEvents = true;
		
		StringBuilder b = new StringBuilder();
		int count = 0;
		for(String s : val)
			{
			s = cleanse(s);
			if(!s.equals("") || retainEmptyStrings)
				{
				if(count>0)
					b.append(displayDelimiter);
				values.add(s);
				b.append(s);
				count++;
				}
			}
		area.setText(b.toString());
		ignoreEvents = false;
		
		if(fire && !values.equals(pVal))
			{
			fireActionEvents();
			flash(Color.GREEN);
			}
		}
	private String cleanse(String val)
		{
		if(filter == null)
			return val;
		return val.replaceAll(filter, "");
		}

	private void parseValue()
		{
		setValue(parseList(area.getText(), parseDelimiter), true);
		}
	
	/**Parse the input string into an ArrayList of substrings based on the given delimiter regex.
	 * Providing a null delimiter will cause the returned list to contain only one element, 
	 * namely the input string itself. This method will retain all empty substrings.*/
	public static ArrayList<String> parseList(String val, String delimiterRegex)
		{
		ArrayList<String> newValues = new ArrayList<String>();
		if(val != null)
			{
			String[] vals = StringArrayEditor.parseStringArray(val, delimiterRegex);
			newValues.addAll(Arrays.asList(vals));
			}
		return newValues;
		}

	synchronized void color(Color color)
		{
		area.setBackground(color);
		}

	private void flash(Color color)
		{
		color(color);
		flashThread(new Runnable(){public void run(){color(origcolor);}}, 33);
		}

	@Override
	public ArrayList<String> getValue()
		{
		return values;
		}

	@Override
	public void setValue(ArrayList<String> val)
		{
		setValue(val, false);
		}

	@Override
	public void setToolTipTextToSubComponents(String text)
		{
		area.setToolTipText(text);
		}

	@Override
	public void setSubComponentsEnabled(boolean en)
		{
		area.setEnabled(en);
		}

	@Override
	public void focusGained(FocusEvent e)
		{}

	@Override
	public void focusLost(FocusEvent e)
		{
		if(!ignoreEvents)
			parseValue();
		}
	
	@Override
	public String getValueString()
		{
		return area.getText();
		}
	}
